/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React from 'react';
import axios from 'axios';
import qs from 'qs';

// Actions
import { requestStart, requestSuccess, requestFailure } from './blockUiActions';
import { queryResultset, queryResultsetError } from './queryResultsetActions';
import { saveOpenQuery } from './workspaceActions';

// UI
import { BlockUi } from '../components/UI';

// Utils
import { Saiku, Settings } from '../utils';

// Types
import {
  SET_CUBE,
  OLAP_QUERY_INIT,
  OLAP_QUERY_RESULT,
  SET_QUERY_PROPERTY,
  RESET_QUERY
} from './types';

// Constants
const { QUERY_PROPERTY_DATA } = Settings;

export const newQuery = (cube, forceResetQuery = false) => dispatch => {
  if (cube && !forceResetQuery) {
    dispatch(setCube({ cube }));
    dispatch(createNewQuery());
  } else if (cube && forceResetQuery) {
    dispatch(setCube({ cube }));
    dispatch(resetQuery());
    dispatch(createNewQuery());
  } else {
    dispatch(resetQuery());
    dispatch(createNewQuery());
  }
};

export const createNewQuery = () => (dispatch, getState) => {
  const { query } = getState().query;
  const uuid = query.name;
  const dataQuery = {
    json: JSON.stringify(query)
  };

  axios
    .post(
      `${Settings.REST_URL}/api/query/${encodeURI(uuid)}`,
      qs.stringify(dataQuery)
    )
    .then(res => {
      const { data } = res;

      dispatch(olapQueryInit(data));
    })
    .catch(error =>
      Saiku.axiosHandleErrors(
        'actions → queryActions.js → createNewQuery()',
        error
      )
    );
};

export const openQuery = params => dispatch => {
  const { uuid, file, formatter } = params;

  axios
    .post(
      `${Settings.REST_URL}/api/query/${encodeURI(uuid)}`,
      qs.stringify({ file, formatter })
    )
    .then(res => {
      const { data } = res;
      const query = data.query || data;
      const queryPropertyData = query.properties[QUERY_PROPERTY_DATA]
        ? JSON.parse(query.properties[QUERY_PROPERTY_DATA])
        : null;

      dispatch(saveOpenQuery(queryPropertyData));
      dispatch(olapQueryRun(query));
    })
    .catch(error =>
      Saiku.axiosHandleErrors('actions → queryActions.js → openQuery()', error)
    );
};

export const setCube = cube => {
  return {
    type: SET_CUBE,
    payload: cube
  };
};

export const olapQueryInit = query => {
  return {
    type: OLAP_QUERY_INIT,
    payload: query
  };
};

export const olapQueryRun = query => (dispatch, getState) => {
  const queryState = getState().query;
  let dataQuery;

  if (query) {
    dataQuery = JSON.stringify(query);
  } else {
    dataQuery = JSON.stringify(queryState.query);
  }

  const actionElem = (
    <button
      className="link-button link-button-action"
      onClick={() => dispatch(olapQueryCancel())}
    >
      [ Cancel ]
    </button>
  );

  dispatch(
    requestStart(<BlockUi message="Running query..." action={actionElem} />)
  );

  axios
    .post(`${Settings.REST_URL}/api/query/execute`, dataQuery, {
      headers: {
        'content-type': 'application/json'
      }
    })
    .then(res => {
      const { data } = res;
      const { query } = data;

      if (data.cellset && query) {
        dispatch(olapQueryResult(query));
        dispatch(queryResultset(data));
      } else {
        dispatch(queryResultsetError(data.error));
      }

      dispatch(requestSuccess());
    })
    .catch(error => {
      dispatch(requestFailure());
      Saiku.axiosHandleErrors(
        'actions → queryActions.js → olapQueryRun()',
        error
      );
    });
};

export const olapQueryCancel = () => (dispatch, getState) => {
  const { query } = getState().query;
  const uuid = query.name;

  dispatch(requestStart(<BlockUi message="Canceling query..." />));

  axios
    .delete(`${Settings.REST_URL}/api/query/${uuid}/cancel`)
    .then(res => dispatch(requestSuccess()))
    .catch(error => {
      dispatch(requestFailure());
      Saiku.axiosHandleErrors(
        'actions → queryActions.js → olapQueryCancel()',
        error
      );
    });
};

export const olapQueryResult = query => {
  return {
    type: OLAP_QUERY_RESULT,
    payload: query
  };
};

export const setQueryProperty = data => {
  return {
    type: SET_QUERY_PROPERTY,
    payload: data
  };
};

export const resetQuery = () => {
  return {
    type: RESET_QUERY
  };
};
